package cn.itcast.nems.journal.service.impl;

import cn.itcast.nems.base.dao.entity.E2Clazz;
import cn.itcast.nems.base.dao.mapper.E2ClazzMapper;
import cn.itcast.nems.common.util.NumberUtil;
import cn.itcast.nems.discounts.dao.dataobject.EmsDiscountsDO;
import cn.itcast.nems.discounts.dao.mapper.EmsDiscountsMapper;
import cn.itcast.nems.journal.dto.JournalTransferLineDiscountCalcParams;
import cn.itcast.nems.journal.dto.JournalTransferLineDiscountCalcResult;
import cn.itcast.nems.journal.dto.JournalTransferLineDiscountCalcResultInfo;
import cn.itcast.nems.journal.service.JournalTransferCommonService;
import cn.itcast.nems.journal.service.JournalTransferLineService;
import cn.itcast.nems.oldems.service.DiscountsService;
import cn.itcast.nems.order.api.JournalDiscountApi;
import cn.itcast.nems.order.dto.JournalDiscountApiReqDTO;
import cn.itcast.nems.product.scheduler.TuitionFeeService;
import cn.itcast.nems.studentrecord.constant.DiscountTypeEnum;
import cn.itcast.nems.studentrecord.dao.entity.JournalTransferLine;
import cn.itcast.nems.studentrecord.dao.mapper.JournalTransferLineMapper;
import cn.itcast.nems.studentrecord.service.studentrecord.StudentRecordService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.itcast.nems.journal.util.TransferUtils.formatPrice;

/**
 * <p>
 * 转班凭单-行 服务实现类
 * </p>
 *
 * @author liyong
 * @since 2023-11-14
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class JournalTransferLineServiceImpl extends ServiceImpl<JournalTransferLineMapper, JournalTransferLine> implements JournalTransferLineService {

    private final StudentRecordService service;
    private final E2ClazzMapper e2ClazzMapper;
    private final TuitionFeeService tuitionFeeService;
    private final EmsDiscountsMapper emsDiscountsMapper;
    private final DiscountsService discountsService;
    private final JournalDiscountApi journalDiscountApi;
    private final JournalTransferCommonService commonService;

    @Override
    public String findLineIdByJobStudentRecordId(String studentRecordId) {
        return super.getBaseMapper().selectLineIdByJobStudentRecordId(studentRecordId);
    }

    @Override
    public String findLineIdByOrderId(String orderId) {
        return super.getBaseMapper().selectLineIdByOrderId(orderId);
    }

    @Override
    public JournalTransferLineDiscountCalcResult discountCalc(JournalTransferLineDiscountCalcParams params) {
        Assert.notNull(params.getOriginClazzOutDate(), "原班级出班日期不能为空");
        final var studentRecord = service.getById(params.getOriginStudentRecordId());
        Assert.notNull(studentRecord, "学籍不存在");
        final var sourceClazz = e2ClazzMapper.selectOne(new QueryWrapper<E2Clazz>().lambda().eq(E2Clazz::getClazzId, studentRecord.getClazzId()));
        Assert.notNull(sourceClazz, "转出班级不存在");
        final var targetClazz = e2ClazzMapper.selectOne(new QueryWrapper<E2Clazz>().lambda().eq(E2Clazz::getClazzId, params.getTargetClazzId()));
        Assert.notNull(targetClazz, "目标班级不存在");
        final var settlementResult = commonService.calculate(
                params.getType(),
                studentRecord,
                params.getOriginClazzOutDate().atTime(0, 0),
                sourceClazz
        );

        var targetClazzOriginalAmount = tuitionFeeService.findTuition(targetClazz.getClazzId(), null)
                .multiply(new BigDecimal(100)).intValue();
        var shouldPayStart = switch (params.getType()) {
            case EXCHANGE, SUSPENSION, DELAY ->
                    studentRecord.getActualAmountDue() - settlementResult.getSettlementAmount();
            default -> targetClazzOriginalAmount;
        };
        List<JournalTransferLineDiscountCalcResultInfo> list = new ArrayList<>();
        List<JournalTransferLineDiscountCalcResultInfo> discountCouponList = new ArrayList<>();
        int targetClazzDiscountAmount = 0;
        if (params.getDiscountIdList() != null && !params.getDiscountIdList().isEmpty()) {
            var shouldPayStartBD = new BigDecimal(shouldPayStart).divide(new BigDecimal(100));
            var dMap = emsDiscountsMapper.findByIdList(params.getDiscountIdList()).stream().collect(Collectors.toMap(EmsDiscountsDO::getId, e -> e));
            for (var discountId : params.getDiscountIdList()) {
                var discount = dMap.get(discountId);
                var discountCalc = discountsService.transferDiscountDTO(discount, shouldPayStartBD);
                var money = new BigDecimal(discountCalc.getShowDiscountMoney()).multiply(new BigDecimal(100)).intValue();
                list.add(new JournalTransferLineDiscountCalcResultInfo(
                        discountCalc.getId(),
                        discountCalc.getDiscountsName(),
                        formatPrice(money), null
                ));
                targetClazzDiscountAmount += money;
            }
        }
        //个人优惠单
        params.setDiscountCouponList(Objects.requireNonNullElse(params.getDiscountCouponList(), new ArrayList<>()));
        for (int i = 0; i < params.getDiscountCouponList().size(); i++) {
            String discountLineId = params.getDiscountCouponList().get(i);
            var shouldPayStartBD = new BigDecimal(shouldPayStart).divide(new BigDecimal(100));
            var discount = journalDiscountApi.queryByLineId(JournalDiscountApiReqDTO.buildForQueryByLineId(discountLineId));
            Assert.notNull(discount, "个人优惠数据未找到");
            var dis = NumberUtil.convertToCent(discount.getDiscountValue());
            // 如果优惠类型为 “折扣” ， 优惠金额 =  执行价格 *  折扣
            if (DiscountTypeEnum.DISCOUNT.name().equalsIgnoreCase(discount.getDiscountType())) {
                dis = NumberUtil.convertToCent(shouldPayStartBD.multiply(discount.getDiscountValue()));
                log.info("【转班计算优惠合计】个人优惠单计算 执行价格：{}，折扣：{} ,结果：{}", shouldPayStartBD.doubleValue(), discount.getDiscountValue(), dis);
            }
            discountCouponList.add(new JournalTransferLineDiscountCalcResultInfo(
                    Integer.valueOf(discount.getDiscountId()),
                    discount.getDiscountName(),
                    formatPrice(dis),
                    discount.getJournalDiscountLineId()
            ));

            targetClazzDiscountAmount += dis;
        }
        // 优惠不能超过应交
        if (targetClazzDiscountAmount > shouldPayStart) {
            targetClazzDiscountAmount = shouldPayStart;
        }
        Integer finalShouldPay = shouldPayStart - targetClazzDiscountAmount;
        Boolean diff = (studentRecord.getActualAmountDue() - settlementResult.getSettlementAmount()) != finalShouldPay;
        Integer diffPrice = (studentRecord.getActualAmountDue() - settlementResult.getSettlementAmount()) - finalShouldPay;

        final var result = new JournalTransferLineDiscountCalcResult();

        result.setOriginClazzOriginalAmountFormatted(formatPrice(studentRecord.getPrice()));
        result.setOriginClazzDiscountAmountFormatted(formatPrice(studentRecord.getDiscountAmount()));
        result.setOriginClazzAmountDueFormatted(formatPrice(studentRecord.getAmountDue()));
        result.setOriginActualAmountDueFormatted(formatPrice(studentRecord.getActualAmountDue()));
        result.setOriginClazzSettlementAmountFormatted(formatPrice(settlementResult.getSettlementAmount()));
        result.setOriginClazzActualSettlementAmountFormatted(result.getOriginClazzSettlementAmountFormatted());
        result.setOriginClazzServiceDays(settlementResult.getServiceDays());
        result.setOriginClazzSettlementDays(settlementResult.getSettlementDays());
        result.setOriginClazzActualSettlementDays(result.getOriginClazzSettlementDays());

        result.setTargetClazzOriginalAmountFormatted(formatPrice(targetClazzOriginalAmount));
        result.setTargetClazzDiscountAmountFormatted(formatPrice(targetClazzDiscountAmount));
        result.setTargetClazzAmountDueFormatted(formatPrice(finalShouldPay));
        result.setTargetClazzActualAmountDueFormatted(formatPrice(finalShouldPay));
        result.setTargetClazzTransferAmountFormatted(formatPrice(settlementResult.getTransferAmount()));

        result.setPriceDifferenceFlag(diff);
        result.setPriceDifferenceAmountFormatted(formatPrice(diffPrice));

        result.setInfoList(list);
        result.setDiscountCouponList(discountCouponList);
        // discountIdList
        return result;
    }

}
